/* hp03.c

Copyright (C) Alex S. (mailto: md5sum@alexsp.ru)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details
http://www.gnu.org/licenses/gpl-2.0.html.

You should have received a copy of the GNU General Public License
along with this program in the file gpl-2.0.txt;
if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "hp03.h"

/*
Внимание! Тактовая частота для hooper hp03 генерируется TIMER1
если Вам надо использовать другой таймер - измените функцию инициялизации
 */

/*Инициализация таймера, датчика (MCLK,XCLR)*/
//#define F_CPU 4000000UL
#define TIMER_PERIOD (((F_CPU/2UL)/32768UL)-1)
#define XCLR_ADC_ON() HOP03_XCLR_PORT|=HOP03_XCLR_MASK
#define XCLR_ADC_OFF() HOP03_XCLR_PORT&=~HOP03_XCLR_MASK

typedef struct {
	uint16_t C1;
	uint16_t C2;
	uint16_t C3;
	uint16_t C4;
	uint16_t C5;
	uint16_t C6;
	uint16_t C7;
	uint8_t	A;
	uint8_t	B;
	uint8_t	C;
	uint8_t	D;
	uint16_t D1;
	uint16_t D2;
} HOP_data_t;

static HOP_data_t HOP_data;

static hop03_ret_status HOP_coefficient(){
#define ifTWI(a) if (TWI_check(a)) {TWI_stop();TWCR=0;return ERROR;}
	uint8_t *p;
	uint8_t i;

	TWI_start();
	ifTWI(TW_START);
	TWI_send_data_nack(HOP03_EEPROM_w);
	ifTWI(TW_MT_SLA_ACK);
	TWI_send_data_nack(HOP03_EEPROM_start);
	ifTWI(TW_MT_DATA_ACK);
	TWI_restart();
	ifTWI(TW_REP_START);
	TWI_send_data_nack(HOP03_EEPROM_r);
	ifTWI(TW_MR_SLA_ACK);


	/*Читаем 18 значений поправок для датчика*/
	p=(uint8_t *)&HOP_data.C1;
	for (i=0;i<17;i++) {
		TWI_send_data_ack(0xff);
		*p=TWDR;
		p++;
	}
	TWI_send_data_nack(0xff);
	*p=TWDR;
	TWI_stop();

	/*Поменяем байты местами, т.к. датчик передает big-endian*/

	/*
	uint16_t *tmp=&HOP_data.C1;
	while (tmp<=&HOP_data.C7) {
	 *tmp=((*tmp>>8)&0x00ff)|((*tmp<<8)&0xff00);
		tmp++;
	}
	 */
	p=(uint8_t *)&HOP_data.C1;
	while (p<=(uint8_t *)&HOP_data.C7) {
		*(uint16_t *)p=((*(uint16_t *)p>>8)&0x00ff)|((*(uint16_t *)p<<8)&0xff00);
		p+=2;
	}
#undef ifTWI

	return SUCCESS;
}

static hop03_ret_status HOP_measure(){
#define ifTWI(a) if (TWI_check(a)){TWI_stop();XCLR_ADC_OFF();TWCR=0;return ERROR;}

	XCLR_ADC_ON();
	//Получаем D1
	TWI_start();
	ifTWI(TW_START);
	TWI_send_data_nack(HOP03_ADC_addrW);
	ifTWI(TW_MT_SLA_ACK);
	TWI_send_data_nack(HOP03_ADC_startcmd);
	ifTWI(TW_MT_DATA_ACK);
	TWI_send_data_nack(HOP03_ADC_D1);
	ifTWI(TW_MT_DATA_ACK);
	TWI_stop();
	/*Ждем 50 мсек*/
	_delay_ms(50);
	/*Читаем результат измерения*/
	TWI_start();
	ifTWI(TW_START);
	TWI_send_data_nack(HOP03_ADC_addrW);
	ifTWI(TW_MT_SLA_ACK);
	TWI_send_data_nack(HOP03_ADC_readcmd);
	ifTWI(TW_MT_DATA_ACK);
	TWI_restart();
	ifTWI(TW_REP_START);
	TWI_send_data_nack(HOP03_ADC_addrR);
	ifTWI(TW_MR_SLA_ACK);
	TWI_send_data_ack(0xff);
	HOP_data.D1=TWDR<<8;
	TWI_send_data_nack(0xff);
	HOP_data.D1|=TWDR;
	TWI_stop();

	// Получаем D2
	TWI_start();
	ifTWI(TW_START);
	TWI_send_data_nack(HOP03_ADC_addrW);
	ifTWI(TW_MT_SLA_ACK);
	TWI_send_data_nack(HOP03_ADC_startcmd);
	ifTWI(TW_MT_DATA_ACK);
	TWI_send_data_nack(HOP03_ADC_D2);
	ifTWI(TW_MT_DATA_ACK);
	TWI_stop();
	/*Ждем 50 мсек*/
	_delay_ms(50);
	/*Читаем результат измерения*/
	TWI_start();
	ifTWI(TW_START);
	TWI_send_data_nack(HOP03_ADC_addrW);
	ifTWI(TW_MT_SLA_ACK);
	TWI_send_data_nack(HOP03_ADC_readcmd);
	ifTWI(TW_MT_DATA_ACK);
	TWI_restart();
	ifTWI(TW_REP_START);
	TWI_send_data_nack(HOP03_ADC_addrR);
	ifTWI(TW_MR_SLA_ACK);
	TWI_send_data_ack(0xff);
	HOP_data.D2=TWDR<<8;
	TWI_send_data_nack(0xff);
	HOP_data.D2|=TWDR;
	TWI_stop();
	XCLR_ADC_OFF();
#undef ifTWI
	return SUCCESS;
}

hop03_ret_status HOP03_init(){

	*(&HOP03_XCLR_PORT-1)|=HOP03_XCLR_MASK;
	*(&HOP03_MCLK_PORT-1)|=HOP03_MCLK_MASK;

	OCR1A=TIMER_PERIOD;
	TCCR1A =(1<<COM1A0)|(0<<FOC1A);
	TCCR1B =(1<<WGM12)|(1<<CS10);
	XCLR_ADC_OFF();
	if (HOP_coefficient()) return ERROR;
	if (HOP_measure()) return ERROR;
	return SUCCESS;
}

hop03_ret_status HOP03_get_value(double *press, double *temp) {
	double dut,off,sens,x;

	if (HOP_measure()) return ERROR;

#if HP03_DEBUG==1

	if ((PIND&(1<<PD4))==0) {
		debug("C1: ");
		itoa(HOP_data.C1,debug_str,10);
		debug(debug_str);
		debug(" C2: ");
		itoa(HOP_data.C2,debug_str,10);
		debug(debug_str);
		debug(" C3: ");
		itoa(HOP_data.C3,debug_str,10);
		debug(debug_str);
		debug(" C4: ");
		itoa(HOP_data.C4,debug_str,10);
		debug(debug_str);
		debug(" C5: ");
		itoa(HOP_data.C5,debug_str,10);
		debug(debug_str);
		debug(" C6: ");
		itoa(HOP_data.C6,debug_str,10);
		debug(debug_str);
		debug(" C7: ");
		itoa(HOP_data.C7,debug_str,10);
		debug(debug_str);

		debug(" A: ");
		itoa(HOP_data.A,debug_str,10);
		debug(debug_str);
		debug(" B: ");
		itoa(HOP_data.B,debug_str,10);
		debug(debug_str);
		debug(" C: ");
		itoa(HOP_data.C,debug_str,10);
		debug(debug_str);
		debug(" D: ");
		itoa(HOP_data.D,debug_str,10);
		debug(debug_str);
		debug(" D1: ");
		itoa(HOP_data.D1,debug_str,10);
		debug(debug_str);
		debug(" D2: ");
		itoa(HOP_data.D2,debug_str,10);
		debug(debug_str);
		debug("\n");
	}
#endif

	if (HOP_data.D2>=HOP_data.C5) {
		//dUT= D2-C5 - ((D2-C5)/2^7) * ((D2-C5)/2^7) * A / 2^C
		dut=((int32_t)HOP_data.D2-(int32_t)HOP_data.C5)-(((int32_t)HOP_data.D2-(int32_t)HOP_data.C5)/(double)128)*(((int32_t)HOP_data.D2-(int32_t)HOP_data.C5)/(double)128)*(int32_t)HOP_data.A/(1L<<HOP_data.C);
	}else{
		//dUT= D2-C5 - ((D2-C5)/2^7) * ((D2-C5)/2^7) * B / 2^C
		dut=((int32_t)HOP_data.D2-(int32_t)HOP_data.C5)-(((int32_t)HOP_data.D2-(int32_t)HOP_data.C5)/(double)128)*(((int32_t)HOP_data.D2-(int32_t)HOP_data.C5)/(double)128)*(int32_t)HOP_data.B/(1L<<HOP_data.C);
	}
	//OFF=(C2+(C4-1024)*dUT/2^14)*4
	off=((int32_t)HOP_data.C2+((int32_t)HOP_data.C4-(double)1024)*dut/(double)16384)*(double)4;
	//SENS = C1+ C3*dUT/2^10
	sens=((int32_t)HOP_data.C1+ (int32_t)HOP_data.C3*dut/(double)1024);
	//X= SENS * (D1-7168)/2^14 - OFF
	x=sens *(HOP_data.D1-(double)7168)/(double)16384-off;
	//P=X*100/2^5+C7*10
	*press= x*(double)100/(double)32+(int32_t)HOP_data.C7*(double)10;
	*press=(*press)*7.600/1013.25+(hop03_correct/10.0);

	// температура
	// T = 250 + dUT * C6 / 2 ^ 16  - dUT/2^D
	*temp=((double)250 + dut*(int32_t)HOP_data.C6/(double)65536 - dut/(1L<<HOP_data.D))/10;
	return SUCCESS;
	//	return (((HOP_data.C1+ HOP_data.C3*dut/1024.0)*(HOP_data.D1-7168.0)/16384.0-((HOP_data.C2+(HOP_data.C4-1024.0)*dut/16384.0)*4.0))*100.0/32.0+HOP_data.C7*10);
}

/*
	C1=29908
	C2=3724
	C3=312
	C4=441
	C5=9191
	C6=3990
	C7=2500
	A=1
	B=4
	C=4
	D=9
	D1=30036
	D2=4107
	HOP_data.C1=29908;
	HOP_data.C2=3724;
	HOP_data.C3=312;
	HOP_data.C4=441;
	HOP_data.C5=9191;
	HOP_data.C6=3990;
	HOP_data.C7=2500;
	HOP_data.A=1;
	HOP_data.B=4;
	HOP_data.C=4;
	HOP_data.D=9;
	HOP_data.D1=30036;
	HOP_data.D2=4107;
 */
